﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ScaffoldIt.Configuration;
using ScaffoldIt.Commands;

namespace ScaffoldIt
{
    partial class FormTemplateSelection : Form
    {
        public FormTemplateSelection()
        {
            InitializeComponent();
        }

        private IEnumerable<Template> SelectedTemplates()
        {
            foreach (TreeNode rootnode in treeViewTemplates.Nodes)
            {
                foreach (var elt in this.SelectedTemplates(rootnode))
                    yield return elt;
            }
        }

        private IEnumerable<Template> SelectedTemplates(TreeNode node)
        {
            if (node.Tag is Template && node.Checked) 
                yield return (node.Tag as Template);

            foreach (TreeNode rootnode in node.Nodes)
            {
                foreach (var elt in this.SelectedTemplates(rootnode))
                    yield return elt;
            }
        }

        public ScaffoldingContext Context { get; private set; }

        private void InitForm(ScaffoldingContext ctx)
        {
            Context = ctx;
            InitPresets(ctx);
            InitTemplates(ctx);
        }

        private void InitPresets(ScaffoldingContext ctx)
        {
            comboBoxPresets.Items.Add("-- No preset --");
            foreach (var preset in ctx.Config.Presets)
            {
                this.InitPreset(ctx, preset);
            }
        }

        private void InitPreset(ScaffoldingContext ctx, Preset preset)
        {
            comboBoxPresets.Items.Add(preset);
        }

        private void InitTemplates(ScaffoldingContext ctx)
        {            
            treeViewTemplates.BeginUpdate();
            foreach (var category in ctx.Config.Categories)
            {
                this.InitTemplatesCategory(ctx, treeViewTemplates.Nodes, category);
            }
            treeViewTemplates.EndUpdate();            
            treeViewTemplates.Refresh();
        }

        private void InitTemplatesCategory(ScaffoldingContext ctx, TreeNodeCollection parent, Category cat)
        {
            TreeNode node = new TreeNode(cat.Name, 0, 0);
            node.Tag = cat;
            node.Checked = false;
            parent.Add(node);

            foreach (var category in cat.Categories)
            {
                this.InitTemplatesCategory(ctx, node.Nodes, category);
            }

            foreach (var template in cat.Templates)
            {
                this.InitTemplate(ctx, node.Nodes, template);
            }
            
        }

        private void InitTemplate(ScaffoldingContext ctx, TreeNodeCollection parent, Template template)
        {
            TreeNode node = new TreeNode(template.Name, 1, 1);
            node.Tag = template;
            parent.Add(node);
        }

        public static IEnumerable<Template> GetTemplates(ScaffoldingContext ctx)
        {
            using (var frm = new FormTemplateSelection())
            {
                frm.InitForm(ctx);
                if (frm.ShowDialog() == DialogResult.OK)
                {
                    ctx.Force = frm.checkBoxForce.Checked;

                    var templates = frm.SelectedTemplates().ToList();
                    if (templates.Count > 0)
                        return templates;
                }
            }

            return null;
        }

        private void comboBoxPresets_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxPresets.SelectedItem != null && comboBoxPresets.SelectedItem is Preset)
            {
                ApplyPreset(comboBoxPresets.SelectedItem as Preset);
            }
        }

        private void ApplyPreset(Preset preset)
        {
            treeViewTemplates.BeginUpdate();
            foreach (TreeNode node in treeViewTemplates.Nodes)
                this.Uncheck(node);

            foreach (TreeNode node in treeViewTemplates.Nodes)
            {
                ApplyPreset(node, null, preset.Categories);
            }
            treeViewTemplates.RefreshTree(); 
            treeViewTemplates.EndUpdate();            
        }
        
        private void Uncheck(TreeNode node)
        {
            node.Checked = false;
            foreach (TreeNode child in node.Nodes)
            {
                this.Uncheck(child);
            }
        }

        private void ApplyPreset(TreeNode rootnode, PresetCategory preset, IList<PresetCategory> presets)
        {                               
            if (rootnode.Tag is Template)
            {
                var category = rootnode.Parent.Tag as Category;
                
                if (preset == null)
                {
                    return;
                }
                
                var templ = rootnode.Tag as Template;
                
                if (preset.HasTemplateName(templ.Name))
                    rootnode.Checked = true;

                return;
            }
            
            if (rootnode.Tag is Category)
            {
                var category = rootnode.Tag as Category;
                var catpreset = presets.FirstOrDefault(p => string.Compare(p.Category, category.Name, true) == 0);

                if (catpreset == null)
                    return;
                
                foreach (TreeNode node in rootnode.Nodes)
                {
                    ApplyPreset(node, catpreset, catpreset.Categories);
                }
            }
        }

        private void treeViewTemplates_AfterSelect(object sender, TreeViewEventArgs e)
        {            
            if (e.Node != null && e.Node.Tag != null)
            {
                if (e.Node.Tag is IDescriptiveElement)
                {
                    var desc = (IDescriptiveElement)e.Node.Tag;
                    labelDescription.Text = desc.Description;
                    return;
                }
            }

            labelDescription.Text = string.Empty;
        }
    }
}
